mod vec2;
mod vec3;
mod vec4;
mod mat4;
mod rect;
mod cuboid;
mod quat;
mod mat3;

pub use vec2::{Vec2, IVec2};
pub use vec3::Vec3;
pub use vec4::Vec4;
pub use mat4::Mat4;
pub use mat3::Mat3;
pub use rect::Rect;
pub use cuboid::Cuboid;
pub use quat::Quat;

#[cfg(test)]
mod test {
    use crate::{Rect, Vec3, Vec4};
    use crate::{Mat4};
    use crate::quat::Quat;

    #[test]
    fn vec3_cross() {
        let a = Vec3(123.0, 456.0, 789.0);
        let b = Vec3(135.0, 246.0, 468.0);
        let c = Vec3::cross(a, b);

        assert_eq!(Vec3::dot(a, c), 0.0);
        assert_eq!(Vec3::dot(b, c), 0.0);
    }

    #[test]
    fn vec3_magnitude() {
        assert_eq!(Vec3(1.0, 1.0, 1.0).magnitude(), f32::sqrt(3.0))
    }

    #[test]
    fn mat4_translate() {
        println!("translate:\n{}", Mat4::translation(1.0, 1.0, 1.0));
    }

    #[test]
    fn mat4_multiply() {
        let a = Mat4::rotation_x(-std::f32::consts::FRAC_PI_2);
        let b = Mat4::translation(0.0, 1.0, 0.0);
        let c = Vec4(0.0, 0.0, 1.0, 1.0);

        println!("a * c:{}", a * c);
        println!("a:\n{}\nb:\n{}", a, b);
        println!("a * 2:\n{}", a * 2.0);
        println!("a * b:\n{}", a * b);
        println!("b * a:\n{}", b * a);
    }

    #[test]
    fn quat_dot() {
        let q = Quat::from_coord(1.0, 2.0, 3.0, 4.0);
        let qa = Quat::from_coord(4.0, 3.0, 2.0, 1.0);
        assert_eq!(q.dot(qa), 20.0);

        assert_eq!(f32::sqrt(q.dot(q)), q.magnitude());
        assert_eq!(q.magnitude(), f32::sqrt(30.0))
    }

    #[test]
    fn quat_rotation() {
        let a = Vec3(1.0, 1.0, 1.0);
        let q = Quat::new(f32::cos(std::f32::consts::FRAC_PI_2), f32::sin(std::f32::consts::FRAC_PI_2) * Vec3(0.0, 1.0, 0.0));
        let qi = q.inv();

        let v = (q * Quat::from(a) * qi).v;

        assert!(f32::abs(-1.0 - v.0) < f32::EPSILON);
        assert!(f32::abs(1.0 - v.1) < f32::EPSILON);
        assert!(f32::abs(-1.0 - v.2) < f32::EPSILON);
    }

    #[test]
    fn rect_includes() {
        let r = Rect::new(50.0, 100.0, 100.0, 50.0);

        assert!(r.includes_xy(75.0, 75.0))
    }

    #[test]
    fn rect_overlay() {
        let ra = Rect::new(50.0, 100.0, 100.0, 50.0);
        let rb = Rect::new(75.0, 90.0, 90.0, 75.0);

        assert!(ra.overlaps(rb))
    }
}
